#include "configmanager.h"
#include "errordialogmanager.h"
#include "preprocessor.h"
#include "qtconcurrentrun.h"
#include "source/ImageProcessor.h"
#include "source/logger.h"
#include "source/tools.h"
#include <QMutexLocker>
#include <QThread>
#include <mutex>

#include <opencv2/features2d.hpp>

PreProcessor &PreProcessor::getInstance()
{
    static PreProcessor _instance;
    return _instance;
}

PreProcessor::PreProcessor(QObject *parent) : QObject(parent),
    m_scaleFactor(ParamValue.getParameter<float>("preprocessing", "scaleFactor")),
    m_fitThreshold(ParamValue.getParameter<float>("preprocessing", "FitThreshold")),
    m_enableTracker(ParamValue.getParameter<bool>("preprocessing", "enableTracker")),
    m_offsetCompensation(ParamValue.getParameter<bool>("preprocessing", "OffsetCompensation")),
    m_enablePreTracking(ParamValue.getParameter<bool>("preprocessing", "enablePreTracking")),
    m_optimalNumber(ParamValue.getParameter<int>("preprocessing", "optimalnumberg")),
    m_trackingAlgorithm(ParamValue.getParameter<int>("preprocessing", "TrackingAlgorithm")),
    m_precisionMatching(ParamValue.getParameter<int>("preprocessing", "precisionMatching")),
    m_identifiThreshold(ParamValue.getParameter<int>("preprocessing", "identifiThreshold")),
    m_identifiThresholdAuto(ParamValue.getParameter<bool>("preprocessing", "identifiThresholdAuto")),
    m_boundaryThreshold(ParamValue.getParameter<int>("preprocessing", "boundaryThreshold")),
    identTracker_(nullptr)
{
    m_matchingsimilarity = 0;
    LogDebug << "Atempting Init PreProcessor";
    initializeTracker(m_trackingAlgorithm);
    QVariantList size = ParamValue.getParameter<QVariantList>("camera","cameraImgSize");


    saveMonitorImgROI = ParamValue.getParameter<QVariantList>("preprocessing","saveMonitorImgROI");
    saveIdentifiImgROI = ParamValue.getParameter<QVariantList>("preprocessing","saveIdentifiImgROI");
    if(saveMonitorImgROI.size() == 4 && saveIdentifiImgROI.size() == 4  )
    {
        // monitorImg_.setRoi(saveMonitorImgROI[0].toInt(),saveMonitorImgROI[1].toInt(),
        //                    saveMonitorImgROI[2].toInt(),saveMonitorImgROI[3].toInt());
        qInfo() << "saveMonitorImgROI : " <<saveMonitorImgROI;
        initfirst = true;

    }

    connect(&CameraEth0::getInstance(),&CameraEth0::isOpenedChanged,this, &PreProcessor::cameraOpenFinish);
    connect(&ConfigManager::getInstance() , &ConfigManager::valueTableLoad,this,&PreProcessor::valueTableLoad);
    LogDebug << "Successuful Init PreProcessor";
}

PreProcessor::~PreProcessor()
{
    LogDebug << "Atempting Init PreProcessor";
    QVariantList size = ParamValue.getParameter("camera","cameraImgSize").toList();
    monitorImg_.setRoi(0,0,size[0].toInt(),size[1].toInt());
    //connect(&ConfigManager::getInstance() , &ConfigManager::configDataChanged,this,&PreProcessor::configDataChanged);
    LogDebug << "Successuful Init PreProcessor";
}


void PreProcessor::processImg(ImageRecord& imgcard)
{
    QReadLocker locker(&mutex);
    QString outtext;
    outtext = "预处理:\n";
    bool isDrawOutput = (ImageProcessor::getInstance().selectedStep()==ImageProcessor::MeauPreProcess);

    //QThread::msleep(1000);
    LogTrack << "Start Preprocess Img";
    cv::Mat img_src = imgcard.getStepImage(StepProcess::Capture);
    cv::Mat img_src_draw = img_src.clone();

    if (img_src.empty()) {
        imgcard.setDefect(8);
        outtext += "原图为空 -> 失败 \n";
        LogError << "Captured image is empty";
        imgcard.setStepImage(StepProcess::Reprogress, img_src,ImageRecord::DisplayCap);
        //imgcard.setState(ImageRecord::Fail);
        return;
    }

    if(initfirst)
    {
        qInfo() << "initfirst into ";
        initfirst =false;
        LogDebug <<"Attempting PreProcessor::resetIdentifiROI()";
        identImg_.setRoi(cv::Rect2d());
        emit identImgRoiChanged();
        identImg_.setImage(cv::Mat());
        ImageProvider::getInstance().image2qml(identImg_.getImage(), "Box2",ImageProvider::defaultImg);
        emit identifiRoiReset();
        cv::Rect2d roi(saveMonitorImgROI[0].toInt(),
                       saveMonitorImgROI[1].toInt(),
                       saveMonitorImgROI[2].toInt(),
                       saveMonitorImgROI[3].toInt());
        if(adjustROI(roi, img_src.size()) == false)
        {
            monitorImg_.setRoi(roi);

            emit monitorImgRoiChanged();

            monitorImg_.setImage(img_src(monitorImg_.getRoi()));
            ImageProvider::getInstance().image2qml(monitorImg_.getImage(), "Box1",ImageProvider::defaultImg);

            cv::Rect2d monitorROI = monitorImg_.getRoi();

            cv::Rect2d inputRect(saveIdentifiImgROI[0].toInt(),
                                 saveIdentifiImgROI[1].toInt(),
                                 saveIdentifiImgROI[2].toInt(),
                                 saveIdentifiImgROI[3].toInt());
            bool isContained = (inputRect.x >= monitorROI.x) &&
                               (inputRect.y >= monitorROI.y) &&
                               (inputRect.x + inputRect.width <= monitorROI.x + monitorROI.width) &&
                               (inputRect.y + inputRect.height <= monitorROI.y + monitorROI.height);
            if(isContained)
            {
                deviationX = inputRect.x - monitorROI.x;
                deviationY = inputRect.y - monitorROI.y;
                cv::Rect2d roi(saveIdentifiImgROI[0].toInt(),
                               saveIdentifiImgROI[1].toInt(),
                               saveIdentifiImgROI[2].toInt(),
                               saveIdentifiImgROI[3].toInt());
                adjustROI(roi, img_src.size());
                identImg_.setImage(img_src(roi));
                identImg_.setRoi(saveIdentifiImgROI[0].toInt(),
                                 saveIdentifiImgROI[1].toInt(),
                                 saveIdentifiImgROI[2].toInt(),
                                 saveIdentifiImgROI[3].toInt());
                cv::Mat IdentImage = identImg_.getImage();
                identifiImgImgChangeSlots(IdentImage);
                emit identImgRoiChanged();
                ImageProvider::getInstance().image2qml(identImg_.getImage(), "Box2",ImageProvider::defaultImg);
                qInfo() << "sucessfull to Init";
            }
        }else
        {
            qWarning() << "fail to Init";
        }

    }

    cv::Mat grayFrame;
    cv::cvtColor(img_src, grayFrame, cv::COLOR_BGR2GRAY);
    imgcard.setCaptureImageGray(grayFrame);

    cv::Rect2d identROI = identImg_.getRoi();
    cv::Rect aDidentROI;
    if(isDrawOutput)
        cv::rectangle(img_src_draw, identROI, cv::Scalar(0, 0, 255), 10, cv::LINE_AA);
    cv::Rect2d finalMonitorROI = monitorImg_.getRoi();
    // 检查是否使用 IdentTracker
    if(m_enableTracker)
    {
        outtext += QString("追踪[ 启用 ] 预追踪[ %1 ]").arg(m_enablePreTracking ? "启动" : "禁用");
        if(!identTracker_)
        {
            imgcard.setDefect(8);
            outtext += "原图为空 -> 失败 \n";
            LogError << "CidentTracker_ is empty";
            imgcard.setStepImage(StepProcess::Reprogress, img_src,ImageRecord::DisplayCap);
            return;
        }
        if (identTracker_->getisInit() && !identROI.empty()) {

            LogTrack << "Using identTracker for detection";
            // 跟踪识别标识位置
            //在相机图上的ROI

            cv::Rect2d trackROI(identROI.x - finalMonitorROI.width * 0.4 + 0.2 * identROI.width,
                                identROI.y - identROI.height * 1,
                                finalMonitorROI.width + 0.5 * identROI.width ,
                                3 * identROI.height );

            adjustROI(trackROI , grayFrame.size());

            if(isDrawOutput)
                cv::rectangle(img_src_draw, trackROI, cv::Scalar(0, 230, 0), 5, cv::LINE_AA);


            cv::Rect2d identToTrack(identROI.x - trackROI.x,
                                    identROI.y - trackROI.y,
                                    identROI.width,
                                    identROI.height);
            bool ret = identTracker_->track(grayFrame(trackROI), identToTrack);  // identROI ->  cap 输出输入基于相机


            m_matchingsimilarity = identTracker_->getsimilarity();
            if(m_matchingsimilarity)
            {
                emit mmatchingsimilarityChanged();
            }
            outtext += "追踪 :" +
                       QString::number(m_matchingsimilarity)
                       + "["+ QString::number(m_fitThreshold) +"]";
            if (!ret || identROI.width <= 0 || identROI.height <= 0) {
                outtext += "-> 失败\n";
                LogWarning << "processImg: Ident tracking failed";
                imgcard.setDefect(1); // 添加缺陷代码 1
            } else {
                identROI.x = identToTrack.x + trackROI.x;
                identROI.y = identToTrack.y + trackROI.y;
                outtext += "-> 成功\n";
                LogTrack << "processImg: Ident tracking success:" << identROI;
                adjustROI(identROI, grayFrame.size());  //基于相机调整

                cv::rectangle(img_src_draw, identROI, cv::Scalar(255, 125, 0), 4, cv::LINE_AA);

                cv::Mat searchIdentImage = identImg_.getImage();
                cv::Rect2d identifyRect = identROI;

                PrecisionIdentify::getInstance().handleIdentifyV2(grayFrame,
                                                                  searchIdentImage ,
                                                                  identifyRect, m_scaleFactor);

                // cv::Rect identifyRect = cv::Rect(0,0,identROI.size().width, identROI.size().height);
                // PrecisionIdentify::getInstancidentInFinalROIe().handleIdentify(grayFrame(identROI),identifyRect); //基于ident


                // identifyRect.x+=identROI.x;
                // identifyRect.y+=identROI.y;
                finalMonitorROI = updateMonitorROI(identROI); //调整基于相机
                if(isDrawOutput)
                {
                    //
                    cv::rectangle(img_src_draw, identROI, cv::Scalar(255, 0, 0), 10, cv::LINE_AA);
                }
                aDidentROI = identROI;
                outtext += "高精度追踪 -> 成功\n";
                identROI = identifyRect;  //调整为
                adjustROI(identROI, grayFrame.size()); //细化

            }
        } else {
            outtext += "追踪 -> 失败：没有设置标识或启动追踪器 \n";
            LogTrack << "Ident tracking not used, using Monitor ROI directly";
        }
        //调整roi防止出界
        //cv::Rect2d imgSrcRoi(0,0,img_src.size().width,img_src.size().height);
        imgcard.isInROI =  adjustROI(finalMonitorROI, grayFrame.size());


        // 如果 identROI 不为空，设置 IdentImage
        if (!identROI.empty()) {
            imgcard.setIdentRoi2src(identROI);
            cv::Rect2d identInFinalROI = cv::Rect2d(
                identROI.x - finalMonitorROI.x,
                identROI.y - finalMonitorROI.y,
                identROI.width,
                identROI.height
                );
            adjustROI(identInFinalROI, finalMonitorROI.size());
            adjustROI(identROI, img_src.size());
            imgcard.setIdentImage(img_src(identROI), identInFinalROI);
            imgcard.setReprogressImageGray(grayFrame(identROI));
            if(isDrawOutput)
                ImageProvider::getInstance().image2qml(img_src(identROI),"Box2");
        }
    }
    else
    {
        outtext += "追踪[ 禁用 ] \n";
    }

    adjustROI(finalMonitorROI, img_src.size());
    if(!monitorImg_.getImage().empty())
        imgcard.setbaseImage(monitorImg_.getImage());


    outtext += "预处理[完成] 设计ROI为"+ QString("x: %1, y: %2, 宽: %3, 高: %4 \n")
                                              .arg(finalMonitorROI.x)
                                              .arg(finalMonitorROI.y)
                                              .arg(finalMonitorROI.width)
                                              .arg(finalMonitorROI.height);

    if(aDidentROI.empty())
        imgcard.moveSpace  = 0;
    else
        imgcard.moveSpace = identImg_.getRoi().x - aDidentROI.x;
    outtext +=  QString("当前偏移:%1\n").arg(imgcard.moveSpace);
    if(isDrawOutput){
        ImageProcessor::getInstance().displayOKNGReson(imgcard.getNgCard());
        ImageProcessor::getInstance().setdetectDetail(outtext);
        cv::rectangle(img_src_draw, finalMonitorROI, cv::Scalar(255, 255, 0), 10, cv::LINE_AA);
        ImageProvider::getInstance().image2qml(img_src(finalMonitorROI),"Box1",ImageProvider::defaultImg);
        ImageProvider::getInstance().image2qml(img_src_draw, "Main",ImageProvider::Capture);
        imgcard.setIsSkipDisplay(true);
        //imgcard.setStepImage(StepProcess::Reprogress, img_src_draw);
    }

    imgcard.setDetectStepTime(Reprogress,outtext);
    imgcard.setMonitorRoi(finalMonitorROI);
    LogTrack << "processImg: Final Monitor ROI " << finalMonitorROI;
    imgcard.setdrawPreoProcessImage(img_src(finalMonitorROI));
    imgcard.setStepImage(StepProcess::Reprogress, img_src(finalMonitorROI),ImageRecord::DisplayPre);
    imgcard.grayImagePre =  grayFrame(finalMonitorROI).clone();
    return;
}


void PreProcessor::setIdentifiImg(cv::Mat img_)
{
    LogDebug << "Attempting to setIdentifiImg ";
    if(img_.empty())
    {
        LogWarning << "setIdentifiImg Fail beacause IdentifiImg is Empty";
        return ;
    }
    if (identTracker_) {
        // identTracker_->initialize(identImg_.getImage(), img_);
    }else{
        LogWarning << "identTracker_ not Init";
    }
    LogDebug << "setIdentifiImg Successfull";
    emit identImgChange(img_);
}

void PreProcessor::setMonitorROI(int x, int y, int width, int height)
{

    cv::Mat displayImg;
    ImageProvider::ImageDisplay displaystep;
    ImageProvider::getInstance().getMainDisplay(displayImg,displaystep);

    if(displayImg.empty())
    {
        LogWarning << "fail to PreProcessor:: setMonitorROI displayImg.empty()";
        ErrorDialogManager::instance().showNonBlockingError("设置基准roi错误", "无法获取主图片");
        return;
    }

    if(width < 20 || height < 20)
    {
        LogError << "Fail to PreProcessor::setMonitorROI width:" << width << ",height:" << height;
        ErrorDialogManager::instance().showNonBlockingError("设置基准roi错误", "尺寸太小");
        return;
    }
    initfirst = false;
    if(displaystep == ImageProvider::Capture)
    {
        resetIdentifiROI();
        QWriteLocker  locker(&mutex);
        monitorImg_.setRoi(x,y,width,height);
        emit monitorImgRoiChanged();
        monitorImg_.setImage(displayImg(monitorImg_.getRoi()));
        ImageProvider::getInstance().image2qml(monitorImg_.getImage(), "Box1",ImageProvider::defaultImg);
        LogDebug <<"[PreProcessor]"<<  QString("Successfull setMonitorROI:%1,%2,%3,%4")
                                            .arg(x).arg(y).arg(width).arg(height);

    }else if(displaystep == ImageProvider::Reprogress)
    {
        cv::Rect2d monitorRoi = monitorImg_.getRoi();
        if(monitorRoi.empty())
        {
            LogError << "Fail to PreProcessor::setMonitorROI displaystep == Reprogress  monitorRoi.empty()";
            ErrorDialogManager::instance().showNonBlockingError("设置基准roi错误", "逻辑错误");
            return;
        }

        resetIdentifiROI();
        QWriteLocker  locker(&mutex);
        monitorImg_.setRoi(x+monitorRoi.x,y+monitorRoi.y,width,height);
        emit monitorImgRoiChanged();
        monitorImg_.setImage(displayImg(cv::Rect2d(x,y,width,height)));
        ImageProvider::getInstance().image2qml(monitorImg_.getImage(), "Box1",ImageProvider::defaultImg);
        LogDebug <<"[PreProcessor]"<<  QString("Successfull setMogetMainDisplaynitorROI:%1,%2,%3,%4")
                                            .arg(x).arg(y).arg(width).arg(height);
    }
    else
    {
        LogError << "Fail to PreProcessor::setMonitorROI :"<< displaystep ;
        ErrorDialogManager::instance().showNonBlockingError("设置基准roi错误", "当前图片投影存在问题，请打开相机");
    }

    if(ImageProcessor::getInstance().selectedStep() == ImageProcessor::MeauBase)
    {
        ImageProcessor::getInstance().setAbortMode(ImageProcessor::OnlyPreProcess);
    }
    QVariantList roi({monitorImg_.getRoi().x , monitorImg_.getRoi().y ,
                      monitorImg_.getRoi().width , monitorImg_.getRoi().height});
    ParamValue.setParameter("preprocessing","saveMonitorImgROI" , roi);
    resetIdentifiROI();
    //emit monitorImgRoiChanged();

}

void PreProcessor::setIdentifiROI(int x, int y, int width, int height)
{
    QWriteLocker  locker(&mutex);
    cv::Mat displayImg;
    ImageProvider::ImageDisplay displaystep;
    ImageProvider::getInstance().getMainDisplay(displayImg,displaystep);
    cv::Rect2d monitorROI = monitorImg_.getRoi();
    if(displayImg.empty())
    {
        LogWarning << "fail to PreProcessor:: setMonitorROI displayImg.empty()";
        ErrorDialogManager::instance().showNonBlockingError("设置标识roi错误", "无法获取主图片");
        return;
    }


    if (monitorROI.empty() || monitorImg_.getRoi().empty())
    {
        ErrorDialogManager::instance().showNonBlockingError("设置标识错误", "请先设置基准....");
        LogWarning << "Attempint setIdentifiROI Must setMonitorROI first";
        return;
    }
    if(width < 20 || height < 20)
    {
        LogError << "Fail to PreProcessor::setIdentifiROI width:" << width << ",height:" << height;
        ErrorDialogManager::instance().showNonBlockingError("设置标识roi错误", "尺寸太小");
        return;
    }
    if(displaystep == ImageProvider::Capture)
    {
        cv::Rect2d inputRect(x, y, width, height);
        bool isContained = (inputRect.x >= monitorROI.x) &&
                           (inputRect.y >= monitorROI.y) &&
                           (inputRect.x + inputRect.width <= monitorROI.x + monitorROI.width) &&
                           (inputRect.y + inputRect.height <= monitorROI.y + monitorROI.height);
        if(isContained)
        {
            deviationX = inputRect.x - monitorROI.x;
            deviationY = inputRect.y - monitorROI.y;
            identImg_.setImage(displayImg(cv::Rect2d(x,y,width,height)));
            identImg_.setRoi(x, y, width, height);
            cv::Mat IdentImage = identImg_.getImage();
            identifiImgImgChangeSlots(IdentImage);
            emit identImgRoiChanged();
            ImageProvider::getInstance().image2qml(identImg_.getImage(), "Box2",ImageProvider::defaultImg);
            LogDebug << QString("Successfully setIdentifiROI(Not Add): %1, %2, %3, %4")
                            .arg(x).arg(y).arg(width).arg(height);
        }
        else
        {
            ErrorDialogManager::instance().showNonBlockingError("设置基准错误", "不在监视框内 ....");
            LogError << "setIdentifiROI Error Not within the monitoring box";
            return;
        }

    }else if(displaystep == ImageProvider::Reprogress)
    {
        identImg_.setImage(displayImg(cv::Rect2d(x,y,width,height)));
        cv::Mat IdentImage = identImg_.getImage();
        identifiImgImgChangeSlots(IdentImage);
        deviationX = x;
        deviationY = y;
        x+=monitorImg_.getRoi().x;
        y+=monitorImg_.getRoi().y;
        identImg_.setRoi(x, y, width, height);
        emit identImgRoiChanged();
        ImageProvider::getInstance().image2qml(identImg_.getImage(), "Box2",ImageProvider::defaultImg);
        LogDebug << QString("Successfully setIdentifiROI: %1, %2, %3, %4")
                        .arg(x).arg(y).arg(width).arg(height);
    }
    else
    {
        LogError << "Fail to PreProcessor::setMonitorROI ";
        ErrorDialogManager::instance().showNonBlockingError("设置基准roi错误", "当前图片投影存在问题，请打开相机");
    }
    QVariantList roi({identImg_.getRoi().x , identImg_.getRoi().y ,
                      identImg_.getRoi().width , identImg_.getRoi().height});
    ParamValue.setParameter("preprocessing","saveIdentifiImgROI" , roi);
}

void PreProcessor::resetMonitorROI()
{
    resetIdentifiROI();
    QWriteLocker  locker(&mutex);
    LogDebug <<"Attempting PreProcessor::resetMonitorROI()";
    monitorImg_.setRoi(cv::Rect2d(0,0,
                                  CameraEth0::getInstance().cameraInfoDetal()["MaxROI_wid"].toInt(),
                                  CameraEth0::getInstance().cameraInfoDetal()["MaxROI_hei"].toInt()));
    emit identImgRoiChanged();
    monitorImg_.setImage(cv::Mat());
    ImageProvider::getInstance().image2qml(monitorImg_.getImage(), "Box1",ImageProvider::defaultImg);
    emit monitorRoiReset();
}


void PreProcessor::resetIdentifiROI()
{
    QWriteLocker  locker(&mutex);
    LogDebug <<"Attempting PreProcessor::resetIdentifiROI()";
    identImg_.setRoi(cv::Rect2d());
    emit identImgRoiChanged();
    identImg_.setImage(cv::Mat());
    ImageProvider::getInstance().image2qml(identImg_.getImage(), "Box2",ImageProvider::defaultImg);
    emit identifiRoiReset();
}

void PreProcessor::testAbort()
{
    cv::Mat image;
    cv::Mat test = image(cv::Rect2d(10,50,60,40));
}

QVariantList PreProcessor::identImgRoi()
{
    cv::Rect2d roi = identImg_.getRoi();
    if(roi.empty())
    {
        return QVariantList({0,0,0,0});
    }
    return QVariantList({roi.x,roi.y,roi.width,roi.height});

}


QVariantList PreProcessor::monitorImgRoi()
{
    cv::Rect2d roi = monitorImg_.getRoi();
    LogDebug << "PreProcessor::monitorImgRoi roi:"  <<roi;
    if(roi.empty())
    {
        return QVariantList({0,0,0,0});
    }
    return QVariantList({roi.x,roi.y,roi.width,roi.height});


}

cv::Rect2d PreProcessor::updateMonitorROI(const cv::Rect2d& identROI)
{
    if(monitorImg_.getRoi().empty())
    {
        LogError<< "Fail updateMonitorROI because: monitorImg_.getRoi is null";
        return cv::Rect2d ();
    }
    cv::Rect2d newMonitorROI(   //更新表示ROI-相机  模板-相机
        identROI.x - deviationX,
        identROI.y - deviationY,
        monitorImg_.getRoi().width,
        monitorImg_.getRoi().height
        );
    LogTrack <<  "successfull updateMonitorROI : " << newMonitorROI;
    return newMonitorROI;
}

void PreProcessor::identifiImgImgChangeSlots(cv::Mat &img)
{
    LogDebug<< "identifiImgImgChangeSlots" << img.cols << "|" << img.rows;
    QtConcurrent::run([this,img]() {
        LogDebug<< "identifiImgImgChangeSlots-run" << img.cols << "|" << img.rows;
        this->identTracker_->initTemplate(img,identImg_.getRoi());
    });
}

void PreProcessor::configDataChanged(const QString &category, const QString &key)
{
    if(category == "preprocessing" && key == "TrackingAlgorithm")
    {
        LogDebug << "go in Slot initializeTracker";
        QtConcurrent::run([this]() {
            int trackerType = ConfigManager::getInstance().getParameter("preprocessing","TrackingAlgorithm").toInt();
            this->initializeTracker(trackerType);
        });
    }
    if(category == "preprocessing" && key == "scaleFactor")
    {
        if(identTracker_!=nullptr)
        {
            float scaleFactor = ConfigManager::getInstance().getParameter("preprocessing","scaleFactor").toFloat();
            identTracker_->setScaleFactor(scaleFactor);
        }
    }

}

void PreProcessor::valueTableLoad()
{
    setTrackingAlgorithm(ParamValue.getParameter<int>("preprocessing", "TrackingAlgorithm"));
    setScaleFactor(ParamValue.getParameter<float>("preprocessing", "scaleFactor"));
    setFitThreshold(ParamValue.getParameter<float>("preprocessing", "FitThreshold"));
    setEnableTracker(ParamValue.getParameter<bool>("preprocessing", "enableTracker"));
    setOffsetCompensation(ParamValue.getParameter<bool>("preprocessing", "OffsetCompensation"));
    setEnablePreTracking(ParamValue.getParameter<bool>("preprocessing", "enablePreTracking"));
    setOptimalNumber(ParamValue.getParameter<int>("preprocessing", "optimalnumberg"));
    setPrecisionMatching(ParamValue.getParameter<int>("preprocessing", "precisionMatching"));
    setIdentifiThreshold(ParamValue.getParameter<int>("preprocessing", "identifiThreshold"));
    setIdentifiThresholdAuto(ParamValue.getParameter<bool>("preprocessing", "identifiThresholdAuto"));
    setBoundaryThreshold(ParamValue.getParameter<int>("preprocessing", "boundaryThreshold"));
    emit contourAreaMinChanged();
}

bool PreProcessor::adjustROI(cv::Rect2d& roi, const cv::Size& imgSize) {
    bool isAdjusted = false;

    // 首先确保ROI的宽度和高度不超过图像的尺寸
    if (roi.width > imgSize.width) {
        roi.width = imgSize.width;
        isAdjusted = true;
    }
    if (roi.height > imgSize.height) {
        roi.height = imgSize.height;
        isAdjusted = true;
    }

    // 调整ROI以确保不超出图像边界
    if (roi.x + roi.width > imgSize.width) {
        roi.x = imgSize.width - roi.width;
        isAdjusted = true;
    }
    if (roi.y + roi.height > imgSize.height) {
        roi.y = imgSize.height - roi.height;
        isAdjusted = true;
    }
    if (roi.x < 0) {
        roi.x = 0;
        isAdjusted = true;
    }
    if (roi.y < 0) {
        roi.y = 0;
        isAdjusted = true;
    }

    // 如果ROI有任何修正，返回false
    if (isAdjusted) {
        LogTrackq << "Adjusted ROI to: (" << roi.x << ", " << roi.y << ", " << roi.width << ", " << roi.height << ")";
        // return isAdjusted;
    }

    // 如果有修正，返回true
    return isAdjusted;
}

void PreProcessor::initializeTracker(int &trackerType)
{
    QMutexLocker locker(&trackerMutex);
    if (identTracker_) {
        delete identTracker_;
    }

    if (trackerType == 1) {
        //ORB
        //identTracker_ = new IdentTrackerORB();
        identTracker_ = new IdentTrackerTemplate(m_scaleFactor);
        LogDebug << "Initialized IdentTrackerORB";
    } else if (trackerType == 0) {
        //Template
        identTracker_ = new IdentTrackerTemplate(m_scaleFactor);
        LogDebug << "Initialized IdentTrackerTemplate";
    } else {
        LogError << "Unknown tracker type: " << trackerType;
        return;
    }
    if(!identImg_.isEmpty())
        identTracker_->initTemplate(identImg_.getImage(),identImg_.getRoi());
}

void PreProcessor::cameraOpenFinish()
{
    if (CameraEth0::getInstance().getIsOpened())
    {
        if(monitorImg_.getRoi().empty())
        {
            LogDebug << "set  PreProcessor Monitor ROI";
            monitorImg_.setRoi(cv::Rect2d(0,0,
                                          CameraEth0::getInstance().cameraInfoDetal()["MaxROI_wid"].toInt(),
                                          CameraEth0::getInstance().cameraInfoDetal()["MaxROI_hei"].toInt()));
            emit identImgRoiChanged();
        }
    }
}


void PreProcessor::setScaleFactor(float scaleFactor)
{
    if(scaleFactor < 0.01)
    {
        ErrorDialogManager::instance().showNonBlockingError("设置缩放比例错误", "无法设置小于0.1的数");
        return ;
    }
    if (m_scaleFactor != scaleFactor) {
        LogDebug << "Setting scaleFactor to " << scaleFactor;
        m_scaleFactor = scaleFactor;
        ParamValue.setParameter("preprocessing", "scaleFactor", scaleFactor);
        if(identTracker_)
            identTracker_->setScaleFactor(m_scaleFactor);
        emit scaleFactorChanged();
    }
}


void PreProcessor::setFitThreshold(float fitThreshold)
{
    if (m_fitThreshold != fitThreshold) {
        LogDebug << "Setting FitThreshold to " << fitThreshold;
        m_fitThreshold = fitThreshold;
        ParamValue.setParameter("preprocessing", "FitThreshold", fitThreshold);
        emit fitThresholdChanged();
    }
}

void PreProcessor::setEnableTracker(bool enable)
{
    if (m_enableTracker != enable) {
        LogDebug << "Setting EnableTracker to " << enable;
        m_enableTracker = enable;
        ParamValue.setParameter("preprocessing", "enableTracker", enable);
        emit enableTrackerChanged();
    }
}

void PreProcessor::setOffsetCompensation(bool enable)
{
    if (m_offsetCompensation != enable) {
        LogDebug << "Setting OffsetCompensation to " << enable;
        m_offsetCompensation = enable;
        ParamValue.setParameter("preprocessing", "OffsetCompensation", enable);
        emit offsetCompensationChanged();
    }
}

void PreProcessor::setEnablePreTracking(bool enable)
{
    if (m_enablePreTracking != enable) {
        LogDebug << "Setting EnablePreTracking to " << enable;
        m_enablePreTracking = enable;
        ParamValue.setParameter("preprocessing", "enablePreTracking", enable);
        emit enablePreTrackingChanged();
    }
}

void PreProcessor::setOptimalNumber(int number)
{
    if (m_optimalNumber != number) {
        LogDebug << "Setting OptimalNumber to " << number;
        m_optimalNumber = number;
        ParamValue.setParameter("preprocessing", "optimalnumberg", number);
        emit optimalNumberChanged();
    }
}

void PreProcessor::setTrackingAlgorithm(int algorithm)
{
    if (m_trackingAlgorithm != algorithm) {
        LogDebug << "Setting TrackingAlgorithm to " << algorithm;
        m_trackingAlgorithm = algorithm;
        initializeTracker(m_trackingAlgorithm);
        ParamValue.setParameter("preprocessing", "TrackingAlgorithm", algorithm);
        emit trackingAlgorithmChanged();
    }
}

void PreProcessor::setPrecisionMatching(int matching)
{
    if (m_precisionMatching != matching) {
        LogDebug << "Setting PrecisionMatching to " << matching;
        m_precisionMatching = matching;
        ParamValue.setParameter("preprocessing", "precisionMatching", matching);
        emit precisionMatchingChanged();
    }
}

void PreProcessor::setIdentifiThreshold(int threshold)
{
    if (m_identifiThreshold != threshold) {
        LogDebug << "Setting IdentifiThreshold to " << threshold;
        m_identifiThreshold = threshold;
        ParamValue.setParameter("preprocessing", "identifiThreshold", threshold);
        emit identifiThresholdChanged();
    }
}

void PreProcessor::setIdentifiThresholdAuto(bool autoThreshold)
{
    if (m_identifiThresholdAuto != autoThreshold) {
        LogDebug << "Setting IdentifiThresholdAuto to " << autoThreshold;
        m_identifiThresholdAuto = autoThreshold;
        ParamValue.setParameter("preprocessing", "identifiThresholdAuto", autoThreshold);
        emit identifiThresholdAutoChanged();
    }
}

void PreProcessor::setBoundaryThreshold(int threshold)
{
    if (m_boundaryThreshold != threshold) {
        LogDebug << "Setting BoundaryThreshold to " << threshold;
        m_boundaryThreshold = threshold;
        ParamValue.setParameter("preprocessing", "boundaryThreshold", threshold);
        emit boundaryThresholdChanged();
    }
}

int PreProcessor::contourAreaMin() const
{
    return ParamValue.getParameter<int>("preprocessing", "contourAreaMin");
}

void PreProcessor::setcontourAreaMin(int contourAreaMin)
{
    ParamValue.setParameter<int>("preprocessing", "contourAreaMin",contourAreaMin);
    emit contourAreaMinChanged();
}

void PreProcessor::getBaseImage(cv::Mat &image)
{
    image = monitorImg_.getImage();
}
